// test_stability.c
#include "test_framework.h"
#include <linux/kthread.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include "../hisi_l0_mem_pool.h"
#include "test_common.h"
#include "test_registration.h"

struct stability_thread_data {
    struct task_struct *task;
    struct completion completion;
    int thread_id;
    volatile bool stop;
    atomic_t *error_count;
    int test_node_id;
};

static int stability_thread(void *data)
{
    struct stability_thread_data *tdata = (struct stability_thread_data *)data;
    void *ptrs[50];
    int i;
    int alloc_count = 0;
    
    // Initialize ptrs array
    memset(ptrs, 0, sizeof(ptrs));
    
    while (!tdata->stop) {
        // Allocate a random number of blocks
        int num_allocs = (alloc_count % 20) + 10; // 10-29 allocations
        
        for (i = 0; i < num_allocs && i < ARRAY_SIZE(ptrs); i++) {
            int size = 32 + (alloc_count % 64) * 32; // 32-2048 bytes
            ptrs[i] = l0_kmalloc(size, tdata->test_node_id);
            if (ptrs[i]) {
                // Fill with pattern
                memset(ptrs[i], (tdata->thread_id + alloc_count + i) & 0xFF, size);
                alloc_count++;
            } else {
                atomic_inc(tdata->error_count);
            }
        }
        
        // Randomly free some blocks
        for (i = 0; i < ARRAY_SIZE(ptrs); i++) {
            if (ptrs[i] && (i % 3 == 0)) { // Free every 3rd allocated block
                l0_kfree(ptrs[i]);
                ptrs[i] = NULL;
            }
        }
        
        // Sleep briefly to avoid overwhelming the system
        msleep(10);
    }
    
    // Clean up any remaining allocations
    for (i = 0; i < ARRAY_SIZE(ptrs); i++) {
        if (ptrs[i]) l0_kfree(ptrs[i]);
    }
    
    complete(&tdata->completion);
    return 0;
}

/**
 * test_long_term_stability - Tests system stability over extended periods
 * 
 * This test verifies:
 * 1. No memory leaks over extended operation
 * 2. System stability under sustained load
 * 3. No resource exhaustion over time
 * 4. Proper cleanup after extended operation
 * 5. Strict validation of all allocation and deallocation operations
 * 
 * Tests long-term system reliability and stability with strict validation
 */
static int test_long_term_stability(struct seq_file *m)
{
#define NUM_THREADS 4
#define TEST_DURATION_MS 30000 // 30 seconds
    
    struct stability_thread_data threads[NUM_THREADS];
    atomic_t error_count;
    int i;
    int passed = 0, total = 0;
    bool has_failures = false;
    int allocation_errors;
    
    atomic_set(&error_count, 0);
    total++;
    
    // Create multiple threads for long-term testing
    for (i = 0; i < NUM_THREADS; i++) {
        init_completion(&threads[i].completion);
        threads[i].thread_id = i;
        threads[i].stop = false;
        threads[i].error_count = &error_count;
        threads[i].test_node_id = get_test_context()->test_node_id;
        
        threads[i].task = kthread_run(stability_thread, &threads[i], 
                                     "l0_stability_thread_%d", i);
        if (IS_ERR(threads[i].task)) {
            TEST_FAIL(m, "Failed to create stability thread %d", i);
            has_failures = true;
            continue;
        }
        TEST_PASS_DEBUG(m, "Successfully created stability thread %d", i);
        passed++;
        total++;
    }
    
    // Verify that all threads were created successfully
    if (passed != (NUM_THREADS + 1)) { // +1 for the initial total++ increment
        TEST_FAIL(m, "Failed to create all stability threads: %d/%d created", passed-1, NUM_THREADS);
        // Clean up any created threads and return
        for (i = 0; i < NUM_THREADS; i++) {
            if (!IS_ERR_OR_NULL(threads[i].task)) {
                threads[i].stop = true;
            }
        }
        // Wait for threads to complete
        for (i = 0; i < NUM_THREADS; i++) {
            if (!IS_ERR_OR_NULL(threads[i].task)) {
                wait_for_completion(&threads[i].completion);
            }
        }
        return -1;
    }
    
    TEST_INFO(m, "Starting %d second stability test with %d threads", 
              TEST_DURATION_MS/1000, NUM_THREADS);
    
    // Run test for specified duration
    msleep(TEST_DURATION_MS);
    
    // Signal threads to stop
    for (i = 0; i < NUM_THREADS; i++) {
        threads[i].stop = true;
    }
    
    // Wait for all threads to complete
    for (i = 0; i < NUM_THREADS; i++) {
        if (!IS_ERR(threads[i].task)) {
            wait_for_completion(&threads[i].completion);
            TEST_PASS_DEBUG(m, "Thread %d completed successfully", i);
            passed++;
            total++;
        } else {
            TEST_FAIL(m, "Thread %d failed to complete", i);
            has_failures = true;
        }
    }
    
    // Check for allocation errors during the test
    allocation_errors = atomic_read(&error_count);
    if (allocation_errors == 0) {
        TEST_PASS(m, "No allocation errors detected during stability test");
        passed++;
        total++;
    } else {
        TEST_FAIL(m, "Detected %d allocation errors during stability test", allocation_errors);
        has_failures = true;
    }
    
    TEST_INFO(m, "Long-term stability test results:");
    TEST_INFO(m, "  Test duration: %d ms", TEST_DURATION_MS);
    TEST_INFO(m, "  Number of threads: %d", NUM_THREADS);
    TEST_INFO(m, "  Allocation errors: %d", allocation_errors);
    
    // Final result
    if (allocation_errors == 0) {
        TEST_PASS(m, "Long-term stability test successful with %d threads for %d ms", 
                  NUM_THREADS, TEST_DURATION_MS);
        passed++;
        total++;
    } else {
        TEST_FAIL(m, "Long-term stability test failed with %d errors", allocation_errors);
    }
    
    TEST_END(m, "Long-term stability tests: %d/%d operations passed", passed, total);
    
    // For strict validation, we require all critical operations to pass
    if (has_failures) {
        TEST_FAIL(m, "Some operations failed during long-term stability tests");
        return -1;
    }
    
    // Check that we had a reasonable number of successful operations
    if (passed > (NUM_THREADS + 3)) { // At least threads created + basic operations
        return 0;
    } else {
        TEST_FAIL(m, "Insufficient successful operations during stability test");
        return -1;
    }
    
#undef NUM_THREADS
#undef TEST_DURATION_MS
}

// Export test cases
static struct test_case test_stability_cases[] = {
    {"Long-term Stability", test_long_term_stability},
};

DECLARE_TEST_MODULE(stability, test_stability_cases)